package com.hsource.doctorcenter.webSocket;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hsource.common.utils.CommonResp;
import com.hsource.doctorcenter.domain.doctor.Doctor;
import com.hsource.doctorcenter.domain.user.UserBase;
import com.hsource.doctorcenter.feign.UserFeignClient;
import com.hsource.doctorcenter.manager.AsyncManager;
import com.hsource.doctorcenter.manager.factory.AsyncFactory;
import com.hsource.doctorcenter.service.api.IApiService;
import com.hsource.doctorcenter.service.doctor.IDoctorService;
import com.hsource.doctorcenter.util.SpringUtils;
import com.hsource.doctorcenter.util.StaticValue;
import com.hsource.doctorcenter.util.StringUtils;
import com.hsource.doctorcenter.util.enums.WebStockMessageEnum;
import javazoom.jl.decoder.Bitstream;
import javazoom.jl.decoder.BitstreamException;
import javazoom.jl.decoder.Header;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

/**
 * @author yangYang
 * @version 1.0
 * @date 2020/10/19 17:21
 * @describe WebSocket服务
 */
@Slf4j
@ServerEndpoint("/ws/{userId}")
@Component
public class WebSocketServer {
    /** Hashtablex线程安全的map用来存储一登录用户信息，key为用户id。**/
    private static Hashtable<String, WebSocketServer> userMap = new Hashtable<>();

    /** 静态变量，用来记录当前在线连接数。**/
    private static int onlineCount = 0;

    /** 与客户端的连接会话。**/
    private Session session;

    /** 与客户端的连接的用户id。**/
    private String userId;

    /**连接打开时执行**/
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) throws IOException{
        System.out.println("新客户端接入，用户ID：" + userId);
        System.out.println("在线人数：" + WebSocketServer.onlineCount);
        if(StringUtils.isNotBlank(userId)){
            this.userId = userId;
            this.session = session;
            // 加入set中
            userMap.put(userId,this);
            // 在线数加1
            addOnlineCount();
        }
        System.out.println("在线人数：" + WebSocketServer.onlineCount);
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        System.out.println("客户端关闭连接："+this.userId);
        /**从map中删除**/
        userMap.remove(this.userId);
        subOnlineCount(); // 在线数减1
        System.out.println("在线人数：" + WebSocketServer.onlineCount);
    }

    /**
     * 收到客户端消息后调用的方法
     * @param message
     * @param session
     */
    @OnMessage
    public void onMessage(String message, Session session) throws MalformedURLException {
        if(StringUtils.isNotBlank(this.userId)){
            //不是心跳检测
            if(!"ping".equals(message)){
                /**收到消息后可以去做一些具体的业务处理在推送，此处直接推送**/
                Map<String,String> stringMap = JSONObject.parseObject(message, Map.class);
                //获取用户信息
                UserFeignClient userFeignClient = SpringUtils.getBean(UserFeignClient.class);
                String ubImage="";
                try{
                    Object userInfo = userFeignClient.getUserInfo(userId);
                    CommonResp commonResps = JSONObject.parseObject(JSONObject.toJSONString(userInfo), CommonResp.class);
                    JSONObject jo= (JSONObject)commonResps.getData();
                    UserBase ub = JSONObject.parseObject(jo.getString("userInfo"), UserBase.class);
                    ubImage=ub.getImage();
                }catch (Exception e){
                    e.printStackTrace();
                }
                stringMap.put("userImage", ubImage);
                IApiService apiService = SpringUtils.getBean(IApiService.class);
                IDoctorService doctorService = SpringUtils.getBean(IDoctorService.class);
                if(stringMap.containsKey("doctorId")) {
                    Doctor doctor = doctorService.selectDoctorByDoctorId(stringMap.get("doctorId"));
                    stringMap.put("doctorImage", doctor.getImage());
                }
                try {
                    JSONArray content = StaticValue.getContent(stringMap.get("type"), stringMap.get("content"));
                    apiService.problemContent(this.userId, JSONObject.toJSONString(content), String.valueOf(stringMap.get("problemId")));
                }catch (ParseException | NoSuchAlgorithmException e){

                }
                stringMap.put("contentType","p");
                stringMap.put("duration","0");
                stringMap.put("imageWidth", "0");
                stringMap.put("imageHeight", "0");
                if(stringMap.get("type").equals("audio")){
                    try {
                        stringMap.put("duration",String.valueOf(WebSocketUtil.getDuration(stringMap.get("content"))+2));
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(stringMap.get("type").equals("image")){
                    String content = stringMap.get("content");
                    Arrays.asList(content.split(",")).stream().forEach(a->{
                        try {
                            BufferedImage file = WebSocketUtil.getBufferedImage(a);
                            stringMap.put("imageWidth", String.valueOf(file.getWidth()));
                            stringMap.put("imageHeight", String.valueOf(file.getHeight()));
                            stringMap.put("content",a);
                        }catch (Exception e){

                        }
                        String s = JSONObject.toJSONString(stringMap);
                        sendMessage(this.userId, s);
                    });

                }else{
                    String s = JSONObject.toJSONString(stringMap);
                    sendMessage(this.userId, s);
                }
                AsyncManager.me().execute(AsyncFactory.refreshProblemDetailTimerTask(this.userId,String.valueOf(stringMap.get("problemId"))));
            }
        }else{
            System.out.println("当前客户未登陆："+this.userId);
        }
        System.out.println("用户【"+this.userId+"】访问");
    }

    /**
     * webstock消息处理
     * @param type
     * @param object
     */
    public static void webStockMessageReverberate(String type, Object object){
        try {
            Class<?> clazz = Class.forName("com.hsource.doctorcenter.manager.factory.callBackService." + WebStockMessageEnum.getServiceImpl(type));
            Method openingService = clazz.getMethod("callBackDataService", Object.class);
            openingService.invoke(clazz.newInstance(), object);
        }catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
            log.error("处理close回调服务失败："+JSONObject.toJSONString(object));
        }
    }
    /**
     * 发生错误时调用
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    public void sendMessage(String userId,String message){
        try {
            if(!StringUtils.isNotBlank(userId)){
                System.out.println("客户ID不能为空");
                return ;
            }
            for(Map.Entry<String, WebSocketServer> entry : userMap.entrySet()){
                if(entry.getKey().equals(userId)){
                    entry.getValue().getSession().getBasicRemote().sendText(message);
                    System.out.println("推送给用户【"+entry.getKey()+"】消息成功，消息为：" + message);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void sendMessage(List<String> userIds, String message){
        try {
            if(userIds == null || userIds.size() == 0){
                System.out.println("客户ID不能为空");
                return ;
            }
            for(Map.Entry<String, WebSocketServer> entry : userMap.entrySet()){
                if(userIds.contains(entry.getKey())){
                    entry.getValue().getSession().getBasicRemote().sendText(message);
                    System.out.println("推送给用户【"+entry.getKey()+"】消息成功，消息为：" + message);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void sendAll(String message){
        try {
            if(!StringUtils.isNotBlank(userId)){
                System.out.println("客户ID不能为空");
                return ;
            }
            for(Map.Entry<String, WebSocketServer> entry : userMap.entrySet()){
                entry.getValue().getSession().getBasicRemote().sendText(message);
                System.out.println("推送给用户【"+entry.getKey()+"】消息成功，消息为：" + message);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //获取连接人数
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }
    //连接人数加一
    public static synchronized void addOnlineCount() {
        onlineCount+=1;
    }
    //连接人数减一
    public static synchronized void subOnlineCount() {
        if(onlineCount > 0){
            onlineCount-=1;
        }
    }

    public Session getSession() {
        return session;
    }

}
